package com.common.operationLog.util;

import com.common.operationLog.annotation.OperationLog;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.*;
import com.xiaopeng.common.enumUtil.EnumView;
import com.xiaopeng.common.enumUtil.EnumViewHandler;
import com.xiaopeng.common.secure.Desensitization;
import com.xiaopeng.common.secure.DesensitizedUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Slf4j
public class OperationLogUtil {

    private static final ObjectMapper objectMapper = new ObjectMapper();

    public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
    public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
    public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";


    public static JsonNode convertJsonNode(Object obj) {
        return new OperationLogHandler().convert(null, obj);
    }

    public static ObjectNode convertObjectNode(Object obj) {
        JsonNode jsonNode = new OperationLogHandler().convert(null, obj);
        if (jsonNode.isObject()) {
            // 处理对象类型
            return (ObjectNode) jsonNode;
        } else if (jsonNode.isArray()) {
            // 处理数组类型
            ObjectNode objectNode = objectMapper.createObjectNode();
            objectNode.set("明细", jsonNode);
            return objectNode;
        } else {
            // 处理基本类型
            return objectMapper.createObjectNode();
        }
    }
    /**
     * 获取所有字段 包括继承的字段
     * @param clazz
     * @return
     */
    private static Field[] getAllFields(Class<?> clazz) {
        List<Field> fields = new ArrayList<>();
        while (clazz != null && clazz != Object.class) {
            fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
            clazz = clazz.getSuperclass();
        }
        return fields.toArray(new Field[0]);
    }

    /**
     * 判断是否为基本类型及其包装类、String等简单类型直接存储
     * @param clazz
     * @return
     */
    private static boolean isSimpleType(Class<?> clazz) {
        return clazz.isPrimitive()
                || clazz == String.class
                || Number.class.isAssignableFrom(clazz)
                || Boolean.class == clazz
                || Character.class == clazz
                || Date.class.isAssignableFrom(clazz)
                || LocalDateTime.class.isAssignableFrom(clazz)
                || Enum.class.isAssignableFrom(clazz);
    }



    private static class OperationLogHandler {


        // 用于避免循环引用导致的无限递归
        private final Set<Object> visitedObjects = Collections.newSetFromMap(new IdentityHashMap<>());

        /**
         *
         * @param objField  当前obj对应的字段
         * @param obj
         * @return
         */
        private JsonNode convert(Field objField, Object obj) {
            if (Objects.isNull(obj)) {
                return NullNode.getInstance();
            }
            Class<?> clazz = obj.getClass();
            // 判断是否基本类型及其包装类、String等简单类型
            if (isSimpleType(clazz)) {
                return getFieldValueNode(objField, obj);
            }

            // 避免循环引用
            if (visitedObjects.contains(obj)) {
                return JsonNodeFactory.instance.textNode("【获取异常】循环引用");
            }
            visitedObjects.add(obj);

            // 处理数组
            if (clazz.isArray()) {
                ArrayNode arrayNode = objectMapper.createArrayNode();
                int length = Array.getLength(obj);
                for (int i = 0; i < length; i++) {
                    Object item = Array.get(obj, i);
                    JsonNode jsonNode = isSimpleType(clazz) ? getFieldValueNode(objField, item) : convert(null, item);
                    arrayNode.add(jsonNode);
                }
                return arrayNode;
            }

            // 处理集合类
            if (obj instanceof Collection<?> srcList) {
                ArrayNode arrayNode = objectMapper.createArrayNode();
                for (Object item : srcList) {
                    JsonNode jsonNode = isSimpleType(clazz) ? getFieldValueNode(objField, item) : convert(null, item);
                    arrayNode.add(jsonNode);
                }
                return arrayNode;
            }

            // 处理Map
            if (obj instanceof Map<?, ?> srcMap) {
                ObjectNode objectNode = objectMapper.createObjectNode();
                for (Map.Entry<?, ?> entry : srcMap.entrySet()) {
                    objectNode.set(entry.getKey().toString(), convert(null, entry.getValue()));
                }
                return objectNode;
            }

            // 处理普通对象
            ObjectNode objectNode = objectMapper.createObjectNode();
            Field[] fields = getAllFields(obj.getClass());
            for (Field field : fields) {
                field.setAccessible(true);
                String fieldNameDesc = getFieldNameDesc(field);
                if (StringUtils.isEmpty(fieldNameDesc)) {
                    continue;
                }
                try {
                    Object value = field.get(obj);
                    JsonNode jsonNode = isSimpleType(clazz) ? getFieldValueNode(field, value) : convert(field, value);
                    objectNode.set(fieldNameDesc, jsonNode);
                } catch (IllegalAccessException e) {
                    objectNode.set(fieldNameDesc, JsonNodeFactory.instance.textNode("【获取异常】无法访问"));
                }
            }
            return objectNode;
        }


        /**
         * 获取字段名描述
         * @return
         */
        private String getFieldNameDesc(Field field) {
            // 复用swagger注解描述
            OperationLog operationLog = field.getAnnotation(OperationLog.class);
            if (Objects.nonNull(operationLog) && StringUtils.isNotEmpty(operationLog.description())) {
                return operationLog.description();
            }
//            return field.getName();
            return null;
        }


        /**
         * 获取字段名描述
         * @return
         */
        private JsonNode getFieldValueNode(Field field, Object value) {
            if (Objects.isNull(value)) {
                return null;
            }
            if (Objects.isNull(field)) {
                return objectMapper.valueToTree(value);
            }
            // 枚举映射
            EnumView excelView = field.getAnnotation(EnumView.class);
            if (Objects.nonNull(excelView)) {
                // 枚举映射
                return TextNode.valueOf(enumCovert(field, excelView, value));
            }
            // 脱敏
            Desensitization desensitization = field.getAnnotation(Desensitization.class);
            if (Objects.nonNull(desensitization)) {
                return TextNode.valueOf(DesensitizedUtils.desensitized(value.toString(), desensitization.value()));
            }
            if (value instanceof LocalDateTime dateTime) {
                return TextNode.valueOf(dateTime.format(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)));
            }
            return objectMapper.valueToTree(value);
        }



        /**
         * 对字段进行枚举映射转换
         * @param field
         * @param excelView
         * @return
         */
        private String enumCovert(Field field, EnumView excelView, Object value) {
            // class模板类名
            String className = field.getDeclaringClass().getName();
            String cacheKey = className + ":" + field.getName();
            try {
                return EnumViewHandler.getNameByCode(excelView, value);
            } catch (Exception e) {
                log.error("Excel导出-获取枚举转换异常 映射字段:{} 异常;{}", cacheKey, e.getMessage(), e);
                throw new RuntimeException(e);
            }
        }

    }
}
